package net.israfil.service.mail.transport.javamail;

import java.io.UnsupportedEncodingException;

import javax.activation.DataHandler;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;

import net.israfil.service.mail.api.MailHeader;
import net.israfil.service.mail.api.MailMessage;
import net.israfil.service.mail.api.MailMessageBody;
import net.israfil.service.mail.api.smtp.PlaintextMessageBody;
import net.israfil.service.mail.api.smtp.SMTPHeaderType;
import net.israfil.service.mail.api.smtp.SMTPHeaderTypes;
import net.israfil.service.mail.api.smtp.SMTPMessage;
import net.israfil.service.mail.api.smtp.SMTPTransport;

public class JavaMailTransport extends SMTPTransport {
	
	private final Session session;

	public JavaMailTransport(Session session) {
		this.session = session;
	}
	
	public boolean send(MailMessage message) {
		if (!(message.getType().equals(TRANSPORT_TYPE))) throw new IllegalArgumentException("Cannot send a non SMTP message to an SMTP transport");
		SMTPMessage smtpMessage = (SMTPMessage) message;
		MimeMessage m = createMimeMessage(smtpMessage);
		try {
			Transport.send(m);
		} catch (MessagingException e) {
			throw new IllegalStateException("Cannot connect to message transport service.",e);
		}
		return false;
	}

	MimeMessage createMimeMessage(SMTPMessage smtpMessage) {
		MimeMessage m = new MimeMessage(session);
		
		for (final MailHeader<?> header : smtpMessage.getHeaders().values()){
			try {
				SMTPHeaderType type = null;
				try {
					type = SMTPHeaderTypes.valueOfCanonicalString(header.getName());
				} catch (IllegalArgumentException e) {
					type = new SMTPHeaderType() {
						public boolean isSingleton() { return false; }
						public String getCanonicalRepresentation() { return header.getName(); }
					};
				}
				if (type.isSingleton()) {
					m.setHeader(type.getCanonicalRepresentation(), MimeUtility.decodeText(header.getStringRepresentation()));
				} else {
					m.addHeader(type.getCanonicalRepresentation(), MimeUtility.decodeText(header.getStringRepresentation()));
				}
			} catch (UnsupportedEncodingException e) {
				throw new IllegalArgumentException("Default coding invalid",e);
			} catch (MessagingException e) {
				throw new IllegalArgumentException("Error converting header to RFC 2047 compliance.",e);
			}
		}
		try {
			m.setDataHandler(getContentAdapter(smtpMessage.getBody()).adapt(smtpMessage.getBody()));
		} catch (MessagingException e) {
			throw new IllegalArgumentException("Error setting message body." ,e);
		}
		return m;
	}
	
	public static ContentAdapter getContentAdapter(MailMessageBody body) {
		if (PlaintextMessageBody.class.equals(body.getClass())) {
			return new ContentAdapter() {
				public DataHandler adapt(MailMessageBody body) {
					DataHandler dh = new DataHandler(new String(body.getBytes("ASCII")),body.getContentType());
					return dh;
				}
			};
		}
		throw new IllegalArgumentException("Unsupported message body type: " + body.getClass());
	}
}
